package com.wy2cloud.esdemo.repository;

import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;

import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import io.searchbox.client.JestClient;
import io.searchbox.client.JestResult;
import io.searchbox.cluster.Health;
import io.searchbox.cluster.NodesInfo;
import io.searchbox.cluster.NodesStats;
import io.searchbox.core.Bulk;
import io.searchbox.core.BulkResult;
import io.searchbox.core.Delete;
import io.searchbox.core.DeleteByQuery;
import io.searchbox.core.DocumentResult;
import io.searchbox.core.Get;
import io.searchbox.core.Index;
import io.searchbox.core.Search;
import io.searchbox.core.SearchResult;
import io.searchbox.core.SearchResult.Hit;
import io.searchbox.core.Update;
import io.searchbox.indices.CloseIndex;
import io.searchbox.indices.CreateIndex;
import io.searchbox.indices.DeleteIndex;
import io.searchbox.indices.Flush;
import io.searchbox.indices.IndicesExists;
import io.searchbox.indices.Optimize;

public abstract class AbstractElasticSearchRepository<T extends Serializable> {
   
	private static final Logger logger = LoggerFactory.getLogger(AbstractElasticSearchRepository.class);
	
	private final Class<T> entityClass; 
    
	@Autowired
    private JestClient jestClient;    

    @SuppressWarnings("unchecked")
	public AbstractElasticSearchRepository() {
        Type genType = getClass().getGenericSuperclass();  
        Type[] params = ((ParameterizedType) genType).getActualTypeArguments();  
        entityClass = (Class<T>) params[0];
        //this.jestClient=jestClient;
    }
    
    
    
    
    public Class<T> getEntityClass() {
		return entityClass;
	}




	public DocumentResult insertDocument(String indexName,String typeName,T entity) throws IOException { 
        Index index = new Index.Builder(entity).index(indexName).type(typeName).build(); 
        DocumentResult documentResult = jestClient.execute(index); 
        return documentResult;
    }
    
    public BulkResult insertDocument(String indexName,String typeName,List<T> entities) throws IOException {
        Bulk.Builder bulk = new Bulk.Builder();
        for(T entity : entities) {
            Index index = new Index.Builder(entity).index(indexName).type(typeName).build();
            bulk.addAction(index);
        }       
        BulkResult buklResult = jestClient.execute(bulk.build());
        return buklResult;
    }
    
    public JestResult updateDocument(String indexName,String typeName, String id,String payload) throws IOException {
        Update update = new Update.Builder(payload).index(indexName).type(typeName).id(id).build();
        JestResult result = jestClient.execute(update);
        return result ;
    }
    public JestResult deleteDocument(String indexName,String typeName, String id) throws IOException {
        Delete delete = new Delete.Builder(id).index(indexName).type(typeName).build();
        JestResult result = jestClient.execute(delete);
        return result;
    }
    public JestResult deleteDocumentByQuery(String indexName,String typeName, String query) throws IOException {

        DeleteByQuery db = new DeleteByQuery.Builder(query)
                .addIndex(indexName)
                .addType(typeName)
                .build();

        JestResult result = jestClient.execute(db);
        return result;
    }
    public T getDocument(String indexName,String typeName, String id) throws IOException {
        Get get = new Get.Builder(indexName, id).type(typeName).build();
        JestResult result = jestClient.execute(get);     
        T entity = result.getSourceAsObject(getEntityClass());
        return entity;

    }
    
    
    public List<Hit<T, Void>> searchAll(String indexName) throws IOException {
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(QueryBuilders.matchAllQuery());
        Search search = new Search.Builder(searchSourceBuilder.toString())
                .addIndex(indexName)
                .build();
        SearchResult result = jestClient.execute(search);
        List<Hit<T, Void>> hits = result.getHits(this.getEntityClass());
        return hits ;
    }
    public List<Hit<T, Void>> search(String keyWord , String indexName, String... highLightFields) throws IOException {
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(QueryBuilders.queryStringQuery(keyWord));
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        for(String field : highLightFields){
            highlightBuilder.field(field);//高亮field
        }
        highlightBuilder.preTags("<em>").postTags("</em>");//高亮标签
        highlightBuilder.fragmentSize(200);//高亮内容长度
        searchSourceBuilder.highlighter(highlightBuilder);
        Search search = new Search.Builder(searchSourceBuilder.toString()).addIndex(indexName).build();
        SearchResult result = jestClient.execute(search);
        List<Hit<T, Void>> hits = result.getHits(getEntityClass());
        return hits ;
    }

    
    public JestResult createIndex(String indexName) throws Exception {  
        JestResult jr = jestClient.execute(new CreateIndex.Builder(indexName).build());  
        return jr;  
    }  
    public JestResult deleteIndex(String indexName) throws IOException {
        DeleteIndex deleteIndex = new DeleteIndex.Builder(indexName).build();
        JestResult result = jestClient.execute(deleteIndex);
        return result ;
    }
    public JestResult closeIndex(String indexName) throws IOException {
        CloseIndex closeIndex = new CloseIndex.Builder(indexName).build(); 
        JestResult result = jestClient.execute(closeIndex);
        return result ;
    }
    
    public JestResult optimizeIndex() throws IOException {
        Optimize optimize = new Optimize.Builder().build(); 
        JestResult result = jestClient.execute(optimize);
        return result ;
    }
    
    public JestResult flushIndex() throws IOException {
        Flush flush = new Flush.Builder().build(); 
        JestResult result = jestClient.execute(flush);
        return result ;
    }
    
    public JestResult indicesExists(String indexName)  throws IOException {
        IndicesExists indicesExists = new IndicesExists.Builder(indexName).build();
        JestResult result = jestClient.execute(indicesExists);
        return result ;
    }
    
    public JestResult nodesInfo() throws IOException {
        NodesInfo nodesInfo = new NodesInfo.Builder().build();
        JestResult result =jestClient.execute(nodesInfo);
        return result ;
    }
    
    public JestResult health() throws IOException {
        Health health = new Health.Builder().build();
        JestResult result = jestClient.execute(health);
        return result ;
    }

    public JestResult nodesStats() throws IOException {
        NodesStats nodesStats = new NodesStats.Builder().build();
        JestResult result = jestClient.execute(nodesStats);
        return result ;
    }
}
